package com.shiyun.disaster_station.station.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.shiyun.disaster_station.common.LocalCacheUtil;
import com.shiyun.disaster_station.common.ReturnMap;
import com.shiyun.disaster_station.enums.CacheEnum;
import com.shiyun.disaster_station.line.bean.po.LineInfoPo;
import com.shiyun.disaster_station.line.bean.po.LineStationRelPo;
import com.shiyun.disaster_station.line.dao.LineInfoMapper;
import com.shiyun.disaster_station.line.dao.LineStationRelMapper;
import com.shiyun.disaster_station.point.bean.po.LinePointPo;
import com.shiyun.disaster_station.point.dao.LinePointMapper;
import com.shiyun.disaster_station.section.bean.po.SectionPo;
import com.shiyun.disaster_station.section.dao.SectionMapper;
import com.shiyun.disaster_station.section.service.SectionService;
import com.shiyun.disaster_station.station.bean.dto.LineTypeDto;
import com.shiyun.disaster_station.station.bean.po.StationPo;
import com.shiyun.disaster_station.station.bean.req.StationImportReq;
import com.shiyun.disaster_station.station.dao.StationMapper;
import com.shiyun.disaster_station.utils.ExcelUtils;
import com.shiyun.disaster_station.utils.GpsUtil;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 类 描 述: 站点
 * 作   者: 史 云
 * 版   本: 1.0.0
 * 时   间: 2022年01月11日  10:00:00
 */
@Service
public class StationService {
    @Resource
    StationMapper stationMapper;
    @Resource
    LineStationRelMapper lineStationRelMapper;
    @Resource
    SectionMapper sectionMapper;
    @Resource
    @Lazy
    SectionService sectionService;
    @Resource
    LinePointMapper linePointMapper;
    @Resource
    LineInfoMapper lineInfoMapper;
    @Resource
    LocalCacheUtil localCacheUtil;

    /**
     * 方法描述: 站点导入
     * 作    者: 史 云
     * 时    间: 2022年05月17日  14:02:32
     */
    public ReturnMap importStation(MultipartFile file, List<String> headerTextList, List<String> headerKeyList) {
        try {
            // 获取导入的数据
            List<StationImportReq> list = ExcelUtils.importExcel(file, headerTextList, headerKeyList, StationImportReq.class);
            // 先判断线路是否存在
            AtomicReference<Set<String>> lineExist = new AtomicReference<>(new HashSet<>());
            existLine(list, lineExist);
            if (!lineExist.get().isEmpty()) {
                return ReturnMap.error(-1, JSONUtil.toJsonStr(lineExist.get()));
            }
            // 获取站点信息:顺便计算系统里程，看看经纬度是否有问题
            AtomicReference<Set<String>> stationRight = getStationPoList(list);
            if (!stationRight.get().isEmpty()) {
                return ReturnMap.error(-1, JSONUtil.toJsonStr(stationRight.get()));
            }
            // 查询线路信息
            List<LineInfoPo> lineList = lineInfoMapper.selectList(null);
            lineList.forEach(lineInfoPo -> {
                // 根据线路查询站点关系表
                List<StationPo> insertList = stationMapper.selectList(new QueryWrapper<StationPo>().eq("line_id", lineInfoPo.getId()));
                // 获取线路站点关系信息
                List<LineStationRelPo> lineStationRelPoList = getLineStationRelPoList(insertList, lineInfoPo.getId());
                // 获取区间数据:必须按线路来分
                List<SectionPo> sectionPoList = getSectionPoList(lineStationRelPoList, lineInfoPo.getId());
            });
            return ReturnMap.ok();
        } catch (IOException e) {
            e.printStackTrace();
            return ReturnMap.error(-1, e.getMessage());
        }
    }

    /**
     * 方法描述: 判断线路是否存在
     * 作    者: 史 云
     * 时    间: 2022年06月17日  09:48:54
     */
    private void existLine(List<StationImportReq> list, AtomicReference<Set<String>> lineExist) {
        list.forEach(item -> {
            String msg = getExistLineMsg(item.getLineName());
            if (msg.startsWith(item.getLineName())) {
                lineExist.get().add(msg);
            }
        });
    }

    /**
     * 方法描述: 检查线路信息是否重复
     * 作    者: 史 云
     * 时    间: 2022年07月19日  14:29:04
     */
    public String getExistLineMsg(String lineName) {
        // 先判断在t_line_info表中不存在
        String lineId = localCacheUtil.getLikeData(CacheEnum.LINE_ID, lineName, "t_line_info", "name", "id");
        if (lineId.equals(lineName)) {
            return lineName + "在线路表t_line_info中不存在。";
        } else {
            // 再判断在t_line_point表中不存在
            boolean existLine = linePointMapper.exists(new QueryWrapper<LinePointPo>().eq("line_id", lineId));
            if (!existLine) {
                return lineName + "在点标识表t_line_point中不存在。";
            }
        }
        return lineId;
    }

    /**
     * 方法描述: 检查站点信息
     * 作    者: 史 云
     * 时    间: 2022年07月19日  14:41:55
     */
    public String getExistStationMsg(String stationName, String lineId) {
        List<StationPo> stationPoList = stationMapper.selectList(new QueryWrapper<StationPo>().eq("name", stationName).eq("line_id", lineId));
        if (CollectionUtil.isEmpty(stationPoList)) {
            return stationName + StringPool.COLON + lineId + "在站点表中不存在";
        }else if(stationPoList.size()>1){
            return stationName + StringPool.COLON + lineId + "在站点表中存在重复数据";
        }
        StationPo stationPo = stationPoList.get(0);
        return String.valueOf(stationPo.getId()+ StringPool.UNDERSCORE +stationPo.getMileage());
    }

    /**
     * 方法描述: 获取区间数据
     * 作    者: 史 云
     * 时    间: 2022年05月20日  15:40:57
     */
    private List<SectionPo> getSectionPoList(List<LineStationRelPo> lineStationRelPoList, String lineId) {
        // 清除区间信息
        sectionMapper.delete(new QueryWrapper<SectionPo>().eq("line_id", lineId));
        // 获取区间信息
        List<SectionPo> sectionPoList = new ArrayList<>(16);
        // 先根据里程排序
        if (CollectionUtil.isNotEmpty(lineStationRelPoList)) {
            for (int i = 0; i < lineStationRelPoList.size() - 1; i++) {
                LineStationRelPo pre = lineStationRelPoList.get(i);
                LineStationRelPo next = lineStationRelPoList.get(i + 1);
                if (pre.getLineId().intValue() == next.getLineId()) {
                    SectionPo sectionPo = new SectionPo();
                    sectionPo.setId(pre.getLineId() * 1000 + i);
                    sectionPo.setCode(pre.getLineName());
                    sectionPo.setName(pre.getStationName() + "-" + next.getStationName());
                    sectionPo.setMileageStart(pre.getCentralMileage());
                    sectionPo.setMileageEnd(next.getCentralMileage());
                    sectionPo.setLineId(pre.getLineId());
                    sectionPo.setStationStartId(pre.getStationId());
                    sectionPo.setStationEndId(next.getStationId());
                    sectionPoList.add(sectionPo);
                }
            }
            // 更新区间
            sectionMapper.insertBatchSomeColumn(sectionPoList);
        }
        return sectionPoList;
    }

    /**
     * 方法描述: 获取线路站点关系信息
     * 作    者: 史 云
     * 时    间: 2022年05月20日  13:42:55
     */
    private List<LineStationRelPo> getLineStationRelPoList(List<StationPo> insertList, String lineId) {
        // 清除线路站点关系表
        lineStationRelMapper.delete(new QueryWrapper<LineStationRelPo>().eq("line_id", lineId));
        // 获取线路站点关系表
        List<LineStationRelPo> lineStationRelPoList = null;
        if (CollectionUtil.isNotEmpty(insertList)) {
            lineStationRelPoList = insertList.stream().sorted(Comparator.comparing(item -> Double.valueOf(item.getCode().replace("K", "").replace("+", ".")))).map(item -> {
                LineStationRelPo ele = new LineStationRelPo();
                ele.setLineId(Integer.valueOf(item.getLineId()));
                ele.setStationId(item.getId());
                ele.setCentralMileage(Double.parseDouble(item.getMileage()));
                ele.setLineName(localCacheUtil.getData(CacheEnum.LINE_NAME, item.getLineId(), "t_line_info", "id", "name"));
                ele.setStationName(item.getName());
                ele.setFlag(1);
                ele.setShowMileage("K" + String.format("%.3f", Double.valueOf(item.getCode())).replace(".", "+"));
                return ele;
            }).collect(Collectors.toList());
            // 新增线路站点关系表
            lineStationRelMapper.insertBatchSomeColumn(lineStationRelPoList);
        }
        return lineStationRelPoList;
    }

    /**
     * 方法描述: 获取站点信息
     * 作    者: 史 云
     * 时    间: 2022年05月20日  11:22:41
     */
    private AtomicReference<Set<String>> getStationPoList(List<StationImportReq> list) {
        // 清除已有的数据
        stationMapper.delete(null);
        // 对象转换
        AtomicReference<Set<String>> mileageRight = new AtomicReference<>(new HashSet<>());
        List<StationPo> insertList = list.stream().filter(item -> {
            boolean outOfChina = GpsUtil.outOfChina(item.getLon(), item.getLat());
            if (outOfChina) {
                mileageRight.get().add(item.getLineName() + ":" + item.getName() + ":" + item.getLon() + ":" + item.getLat() + ":经纬度超出中国范畴。");
            }
            return !outOfChina;
        }).map(item -> {
            StationPo ele = BeanUtil.toBean(item, StationPo.class);
            // 设置线路信息
            String lineId = localCacheUtil.getLikeData(CacheEnum.LINE_ID, item.getLineName(), "t_line_info", "name", "id");
            ele.setLineId(lineId);
            // 设置info字段
            ele.fillInfo(item);
            // 设置打桩标号里程
            ele.setCode(String.valueOf(item.getMileage()));
            // 设置系统里程
            ele.setMileage(linePointMapper.getMileageByLoc(lineId, item.getLon(), item.getLat()).getStr("mileage"));
            return ele;
        }).collect(Collectors.toList());
        // 参数设置
        for (int i = 0; i < insertList.size(); i++) {
            StationPo item = insertList.get(i);
            item.setId(i + 1);
        }
        // 批量查询站点表
        if (mileageRight.get().isEmpty()) {
            stationMapper.insertBatchSomeColumn(insertList);
        }
        return mileageRight;
    }

    /**
     * 方法描述: 更新站点的里程
     * 作    者: 史 云
     * 时    间: 2022年06月06日  10:34:48
     */
    public void updateStationMileage(String lineId) {
        // 获取站点信息
        List<StationPo> stationList = stationMapper.selectList(new QueryWrapper<StationPo>().eq("line_id", lineId));
        if (CollectionUtil.isNotEmpty(stationList)) {
            // 计算站点的里程
            for (StationPo stationPo : stationList) {
                String mileage = linePointMapper.getMileageByLoc(lineId, stationPo.getLon(), stationPo.getLat()).getStr("mileage");
                stationPo.setMileage(mileage);
            }
            // 更新站点的里程
            stationMapper.updateBatch(stationList);
            // 更新线路站点关系表
            List<LineStationRelPo> lineStationRelPoList = getLineStationRelPoList(stationList, lineId);
            // 新增区间表信息:没有区间表了
//            sectionService.updateMileage(lineStationRelPoList, lineId);
        }
    }

    /**
     * 方法描述: 查询异常站点
     * 作    者: 史 云
     * 时    间: 2022年06月18日  15:26:06
     */
    public ReturnMap getUnSolveStation(MultipartFile file, List<String> headerTextList, List<String> headerKeyList) {
        try {
            // 获取导入的数据
            List<StationImportReq> list = ExcelUtils.importExcel(file, headerTextList, headerKeyList, StationImportReq.class);
            Set<String> importStation = list.stream().map(item -> item.getName()).collect(Collectors.toSet());
            // 查询区间表
            Set<String> usefulStationSet = new HashSet<>();
            sectionMapper.selectList(null).forEach(item -> {
                usefulStationSet.addAll(Arrays.asList(item.getName().split("-")));
            });
            // 获取差集
            Collection<String> subtractStation = CollUtil.subtract(importStation, usefulStationSet);
            return ReturnMap.ok(subtractStation);
        } catch (IOException e) {
            e.printStackTrace();
            return ReturnMap.error(-1, e.getMessage());
        }
    }

    /**
     * 方法描述: 更新站点的线路类型
     * 作    者: 史 云
     * 时    间: 2022年08月25日  16:23:43
     */
    public ReturnMap updateLineType() {
        // 查询所有线路ID和类型
        List<LineTypeDto> lineList = stationMapper.selectLineIdAndType();
        // 根据ID查询站点
        lineList.forEach(line->{
            // 更新站点的线路类型
            int updateExe = stationMapper.updateLineType(line.getLineId(), line.getLineType());
            System.out.println(updateExe+">>>>>>>>>>>>>");
        });
        return ReturnMap.ok();
    }
}
